package com.kindac.together.av;

import javax.microedition.khronos.opengles.GL10;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.camera.hud.controls.AnalogOnScreenControl;
import org.anddev.andengine.engine.camera.hud.controls.AnalogOnScreenControl.IAnalogOnScreenControlListener;
import org.anddev.andengine.engine.camera.hud.controls.BaseOnScreenControl;
import org.anddev.andengine.engine.handler.physics.PhysicsHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.modifier.AlphaModifier;
import org.anddev.andengine.entity.modifier.ParallelEntityModifier;
import org.anddev.andengine.entity.modifier.ScaleModifier;
import org.anddev.andengine.entity.modifier.SequenceEntityModifier;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.background.AutoParallaxBackground;
import org.anddev.andengine.entity.scene.background.ParallaxBackground.ParallaxEntity;
import org.anddev.andengine.entity.scene.menu.MenuScene;
import org.anddev.andengine.entity.scene.menu.MenuScene.IOnMenuItemClickListener;
import org.anddev.andengine.entity.scene.menu.item.IMenuItem;
import org.anddev.andengine.entity.scene.menu.item.SpriteMenuItem;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.text.Text;
import org.anddev.andengine.entity.text.TickerText;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.extension.input.touch.controller.MultiTouch;
import org.anddev.andengine.extension.input.touch.controller.MultiTouchController;
import org.anddev.andengine.extension.input.touch.exception.MultiTouchException;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.HorizontalAlign;

import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.view.KeyEvent;

import com.kindac.together.common.Kin;
import com.kindac.together.service.HeadService;
import com.kindac.together.uitl.Utils;

/**
 * @author Nicolas Gramlich
 * @since 19:58:39 - 19.07.2010
 */
public class AutoParallaxBackgroundExample extends BaseGameActivity implements IOnMenuItemClickListener {

    // ===========================================================
    // Constants
    // ===========================================================

    private static final int      CAMERA_WIDTH  = 845;
    private static final int      CAMERA_HEIGHT = 480;

    // ===========================================================
    // Fields
    // ===========================================================

    private Camera                mCamera;

    private Texture               mTexture;
    private TiledTextureRegion    mPlayerTextureRegion;
    private TiledTextureRegion    mEnemyTextureRegion;

    private Texture               mAutoParallaxBackgroundTexture;

    // 背景
    private TextureRegion         mParallaxLayerBack;
    private TextureRegion         mParallaxLayerMid;
    private TextureRegion         mParallaxLayerFront;

    protected static final int    MENU_RESET    = 0;
    protected static final int    MENU_QUIT     = MENU_RESET + 1;

    // menu
    private MenuScene             mMenuScene;
    private Scene                 mMainScene;
    private Texture               mMenuTexture;
    private TextureRegion         mMenuResetTextureRegion;
    private TextureRegion         mMenuQuitTextureRegion;

    // 字
    private Texture               mFontTexture;
    private Font                  mFont;
    private Text                  text;
    private int                   number;
    private boolean               exit          = false;
    private TimerHandler          timerHandler;

    // 控制器
    private Texture               mOnScreenControlTexture;
    private TextureRegion         mOnScreenControlBaseTextureRegion;
    private TextureRegion         mOnScreenControlKnobTextureRegion;

    private static float          curYouX       = 0;
    private static float          curYouY       = 0;
    private static float          curMeX        = 0;
    private static float          curMeY        = 0;
    private AnalogOnScreenControl digitalOnScreenControl;

    // ===========================================================
    // Constructors
    // ===========================================================

    // ===========================================================
    // Getter & Setter
    // ===========================================================

    // ===========================================================
    // Methods for/from SuperClass/Interfaces
    // ===========================================================

    @Override
    public Engine onLoadEngine() {
        this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
        Engine engine = new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE,
                                                     new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
                                                     this.mCamera));

        try {
            if (MultiTouch.isSupported(this)) {
                engine.setTouchController(new MultiTouchController());
                if (MultiTouch.isSupportedDistinct(this)) {
                    System.out.println("MultiTouch detected --> Both controls will work properly!");
                } else {
                    System.out.println("MultiTouch detected, but your device has problems distinguishing between fingers.\n\nControls are placed at different vertical locations.");
                }
            } else {
                System.out.println("Sorry your device does NOT support MultiTouch!\n\n(Falling back to SingleTouch.)\n\nControls are placed at different vertical locations.");
            }
        } catch (final MultiTouchException e) {
            System.out.println("Sorry your Android Version does NOT support MultiTouch!\n\n(Falling back to SingleTouch.)\n\nControls are placed at different vertical locations.");
        }
        return engine;
    }

    @Override
    public void onLoadResources() {

        Kin.curAct = this;

        // 背景音乐
        startService(new Intent(this, HeadService.class).setAction(Kin.MUSIC));

        this.mTexture = new Texture(256, 128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        this.mPlayerTextureRegion = TextureRegionFactory.createTiledFromAsset(this.mTexture, this, "gfx/player1.png",
                                                                              0, 0, 3, 4);
        this.mEnemyTextureRegion = TextureRegionFactory.createTiledFromAsset(this.mTexture, this, "gfx/player2.png",
                                                                             97, 0, 3, 4);

        this.mAutoParallaxBackgroundTexture = new Texture(1024, 1024, TextureOptions.DEFAULT);
        this.mParallaxLayerFront = TextureRegionFactory.createFromAsset(this.mAutoParallaxBackgroundTexture, this,
                                                                        "gfx/parallax_background_layer_front.png", 0, 0);
        this.mParallaxLayerBack = TextureRegionFactory.createFromAsset(this.mAutoParallaxBackgroundTexture, this,
                                                                       "gfx/parallax_background_layer_back.png", 0, 188);
        this.mParallaxLayerMid = TextureRegionFactory.createFromAsset(this.mAutoParallaxBackgroundTexture, this,
                                                                      "gfx/parallax_background_layer_mid.png", 0, 669);

        this.mEngine.getTextureManager().loadTextures(this.mTexture, this.mAutoParallaxBackgroundTexture);

        this.mMenuTexture = new Texture(256, 128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        this.mMenuResetTextureRegion = TextureRegionFactory.createFromAsset(this.mMenuTexture, this,
                                                                            "gfx/menu_back.png", 0, 0);
        this.mMenuQuitTextureRegion = TextureRegionFactory.createFromAsset(this.mMenuTexture, this,
                                                                           "gfx/menu_quit.png", 0, 50);
        this.mEngine.getTextureManager().loadTexture(this.mMenuTexture);

        this.mFontTexture = new Texture(256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);

        this.mFont = new Font(this.mFontTexture, Typeface.createFromAsset(getBaseContext().getAssets(),
                                                                          "font/UnrealTournament.ttf"), 32, true,
                              Color.WHITE);
        this.mEngine.getFontManager().loadFont(this.mFont);
        this.mEngine.getTextureManager().loadTexture(this.mFontTexture);

        this.mOnScreenControlTexture = new Texture(256, 128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        this.mOnScreenControlBaseTextureRegion = TextureRegionFactory.createFromAsset(this.mOnScreenControlTexture,
                                                                                      this,
                                                                                      "gfx/onscreen_control_base.png",
                                                                                      0, 0);
        this.mOnScreenControlKnobTextureRegion = TextureRegionFactory.createFromAsset(this.mOnScreenControlTexture,
                                                                                      this,
                                                                                      "gfx/onscreen_control_knob.png",
                                                                                      128, 0);

        this.mEngine.getTextureManager().loadTextures(this.mTexture, this.mOnScreenControlTexture);
    }

    @Override
    public Scene onLoadScene() {

        this.mEngine.registerUpdateHandler(new FPSLogger());

        this.createMenuScene();

        this.mMainScene = new Scene(1);

        createBackground();

        if (Kin.isWrite) createFont();

        createYouAndMe();

        return this.mMainScene;
    }

    @Override
    public void onLoadComplete() {
    }

    private void createBackground() {

        final AutoParallaxBackground autoParallaxBackground = new AutoParallaxBackground(0, 0, 0, 5);
        autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(
                                                                       0.0f,
                                                                       new Sprite(
                                                                                  0,
                                                                                  CAMERA_HEIGHT
                                                                                          - this.mParallaxLayerBack.getHeight(),
                                                                                  this.mParallaxLayerBack)));
        autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(-5.0f, new Sprite(0, 80, this.mParallaxLayerMid)));
        autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(
                                                                       -10.0f,
                                                                       new Sprite(
                                                                                  0,
                                                                                  CAMERA_HEIGHT
                                                                                          - this.mParallaxLayerFront.getHeight(),
                                                                                  this.mParallaxLayerFront)));
        this.mMainScene.setBackground(autoParallaxBackground);
    }

    private void createFont() {
        final float pX;
        final float pY;
        if (Kin.disPlay == Kin.large) {
            pX = Kin.mWidth / 6;
            pY = Kin.mHeight / 3;
        } else if (Kin.disPlay == Kin.mini) {
            pX = Kin.mWidth / 4;
            pY = Kin.mHeight / 3 + 50;
        } else {
            pX = Kin.mWidth / 4;
            pY = Kin.mHeight / 2 + 30;
        }

        text = new TickerText(pX, pY, this.mFont, this.getResources().getString(Kin.lastString[number]),
                              HorizontalAlign.CENTER, 15);
        text.registerEntityModifier(new SequenceEntityModifier(new ParallelEntityModifier(new AlphaModifier(12, 0.5f,
                                                                                                            1.0f),
                                                                                          new ScaleModifier(5, 0.5f,
                                                                                                            1.0f)),
                                                               new ParallelEntityModifier(new AlphaModifier(5, 1.0f,
                                                                                                            -1.0f),
                                                                                          new ScaleModifier(10, 1.0f,
                                                                                                            0.5f))));

        text.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        this.mMainScene.getLastChild().attachChild(text);

        timerHandler = new TimerHandler(15, true, new ITimerCallback() {

            @Override
            public void onTimePassed(final TimerHandler pTimerHandler) {

                number++;
                text = new TickerText(pX, pY, mFont, getResources().getString(Kin.lastString[number]),
                                      HorizontalAlign.CENTER, 15);
                if (number == Kin.lastString.length - 1) {
                    exit = true;
                    text.registerEntityModifier(new SequenceEntityModifier(
                                                                           new ParallelEntityModifier(
                                                                                                      new AlphaModifier(
                                                                                                                        15,
                                                                                                                        0.5f,
                                                                                                                        1.0f),
                                                                                                      new ScaleModifier(
                                                                                                                        5,
                                                                                                                        0.5f,
                                                                                                                        1.0f))));
                } else {
                    text.registerEntityModifier(new SequenceEntityModifier(
                                                                           new ParallelEntityModifier(
                                                                                                      new AlphaModifier(
                                                                                                                        15,
                                                                                                                        0.5f,
                                                                                                                        1.0f),
                                                                                                      new ScaleModifier(
                                                                                                                        5,
                                                                                                                        0.5f,
                                                                                                                        1.0f)),
                                                                           new ParallelEntityModifier(
                                                                                                      new AlphaModifier(
                                                                                                                        5,
                                                                                                                        1.0f,
                                                                                                                        -1.0f),
                                                                                                      new ScaleModifier(
                                                                                                                        10,
                                                                                                                        1.0f,
                                                                                                                        0.5f))));
                }
                text.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
                mMainScene.getLastChild().attachChild(text);

                if (exit) mMainScene.unregisterUpdateHandler(timerHandler);

            }
        });
        this.mMainScene.registerUpdateHandler(timerHandler);
    }

    private void createYouAndMe() {

        /* Calculate the coordinates for the face, so its centered on the camera. */
        final int playerX = (CAMERA_WIDTH - this.mPlayerTextureRegion.getTileWidth()) / 2;
        final int playerY = CAMERA_HEIGHT - this.mPlayerTextureRegion.getTileHeight();

        /* Create two sprits and add it to the scene. */
        final AnimatedSprite you = new AnimatedSprite(playerX + 20, playerY, this.mPlayerTextureRegion);
        you.setScaleCenterY(this.mPlayerTextureRegion.getTileHeight());
        you.setScale(2);
        you.animate(new long[] { 200, 200, 200 }, 6, 8, true);

        final AnimatedSprite me = new AnimatedSprite(playerX + 80, playerY, this.mEnemyTextureRegion);
        me.setScaleCenterY(this.mEnemyTextureRegion.getTileHeight());
        me.setScale(2);
        me.animate(new long[] { 200, 200, 200 }, 6, 8, true);

        this.mMainScene.getLastChild().attachChild(me);
        this.mMainScene.getLastChild().attachChild(you);

        final PhysicsHandler physicsHandler = new PhysicsHandler(you);
        final PhysicsHandler physicsHandler2 = new PhysicsHandler(me);

        you.registerUpdateHandler(physicsHandler);
        me.registerUpdateHandler(physicsHandler2);

        final int x = CAMERA_WIDTH - this.mOnScreenControlBaseTextureRegion.getWidth() - 30;
        final int y = CAMERA_HEIGHT - this.mOnScreenControlBaseTextureRegion.getHeight();

        digitalOnScreenControl = new AnalogOnScreenControl(0, y, this.mCamera, this.mOnScreenControlBaseTextureRegion,
                                                           this.mOnScreenControlKnobTextureRegion, 0.1f,
                                                           new IAnalogOnScreenControlListener() {

                                                               @Override
                                                               public void onControlChange(final BaseOnScreenControl pBaseOnScreenControl,
                                                                                           final float pValueX,
                                                                                           final float pValueY) {
                                                                   if (curYouX != pValueX && pValueX == 1) {
                                                                       curYouX = pValueX;
                                                                       you.animate(new long[] { 200, 200, 200 }, 6, 8,
                                                                                   true);
                                                                   } else if (curYouX != pValueX && pValueX == -1) {
                                                                       curYouX = pValueX;
                                                                       you.animate(new long[] { 200, 200, 200 }, 3, 5,
                                                                                   true);
                                                                   } else if (curYouY != pValueY && pValueY == 1) {

                                                                       curYouY = pValueY;
                                                                       you.animate(new long[] { 200, 200, 200 }, 0, 2,
                                                                                   true);
                                                                   } else if (curYouY != pValueY && pValueY == -1) {
                                                                       curYouY = pValueY;
                                                                       you.animate(new long[] { 200, 200, 200 }, 9, 11,
                                                                                   true);
                                                                   }
                                                                   physicsHandler.setVelocity(pValueX * 100,
                                                                                              pValueY * 100);
                                                               }

                                                               @Override
                                                               public void onControlClick(final AnalogOnScreenControl pAnalogOnScreenControl) {
                                                               }
                                                           });
        digitalOnScreenControl.getControlBase().setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        digitalOnScreenControl.getControlBase().setAlpha(0.5f);

        mMainScene.setChildScene(digitalOnScreenControl);

        /* Rotation control (right). */
        final AnalogOnScreenControl rotationOnScreenControl = new AnalogOnScreenControl(
                                                                                        x,
                                                                                        y,
                                                                                        this.mCamera,
                                                                                        this.mOnScreenControlBaseTextureRegion,
                                                                                        this.mOnScreenControlKnobTextureRegion,
                                                                                        0.1f,
                                                                                        new IAnalogOnScreenControlListener() {

                                                                                            @Override
                                                                                            public void onControlChange(final BaseOnScreenControl pBaseOnScreenControl,
                                                                                                                        final float pValueX,
                                                                                                                        final float pValueY) {

                                                                                                if (curMeX != pValueX
                                                                                                    && pValueX == 1) {
                                                                                                    curMeX = pValueX;
                                                                                                    me.animate(new long[] {
                                                                                                                       200,
                                                                                                                       200,
                                                                                                                       200 },
                                                                                                               6, 8,
                                                                                                               true);
                                                                                                } else if (curMeX != pValueX
                                                                                                           && pValueX == -1) {
                                                                                                    curMeX = pValueX;

                                                                                                    me.animate(new long[] {
                                                                                                                       200,
                                                                                                                       200,
                                                                                                                       200 },
                                                                                                               3, 5,
                                                                                                               true);

                                                                                                } else if (curMeY != pValueY
                                                                                                           && pValueY == 1) {
                                                                                                    curMeY = pValueY;
                                                                                                    me.animate(new long[] {
                                                                                                                       200,
                                                                                                                       200,
                                                                                                                       200 },
                                                                                                               0, 2,
                                                                                                               true);
                                                                                                } else if (curMeY != pValueY
                                                                                                           && pValueY == -1) {
                                                                                                    curMeY = pValueY;

                                                                                                    me.animate(new long[] {
                                                                                                                       200,
                                                                                                                       200,
                                                                                                                       200 },
                                                                                                               9, 11,
                                                                                                               true);

                                                                                                }
                                                                                                physicsHandler2.setVelocity(pValueX * 100,
                                                                                                                            pValueY * 100);
                                                                                            }

                                                                                            @Override
                                                                                            public void onControlClick(final AnalogOnScreenControl pAnalogOnScreenControl) {
                                                                                                /* Nothing. */
                                                                                            }
                                                                                        });
        rotationOnScreenControl.getControlBase().setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        rotationOnScreenControl.getControlBase().setAlpha(0.5f);

        digitalOnScreenControl.setChildScene(rotationOnScreenControl);

    }

    @Override
    public boolean onKeyDown(final int pKeyCode, final KeyEvent pEvent) {
        if (pKeyCode == KeyEvent.KEYCODE_BACK && pEvent.getAction() == KeyEvent.ACTION_DOWN) {

            startService(new Intent(this, HeadService.class).setAction(Kin.PAUSE));

            this.mMainScene.setChildScene(this.mMenuScene, false, true, true);

            return true;
        } else {
            return super.onKeyDown(pKeyCode, pEvent);
        }
    }

    public boolean onMenuItemClicked(final MenuScene pMenuScene, final IMenuItem pMenuItem,
                                     final float pMenuItemLocalX, final float pMenuItemLocalY) {
        switch (pMenuItem.getID()) {
            case MENU_RESET:
                this.mMenuScene.closeMenuScene();
                mMainScene.setChildScene(digitalOnScreenControl);
                startService(new Intent(this, HeadService.class).setAction(Kin.MUSIC));
                return true;
            case MENU_QUIT:
                /* End Activity. */
                mMainScene.unregisterUpdateHandler(timerHandler);
                Utils.killProcess(this);
                this.finish();
                return true;
            default:
                return false;
        }
    }

    // ===========================================================
    // Methods
    // ===========================================================

    protected void createMenuScene() {
        this.mMenuScene = new MenuScene(this.mCamera);

        final SpriteMenuItem resetMenuItem = new SpriteMenuItem(MENU_RESET, this.mMenuResetTextureRegion);
        resetMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        this.mMenuScene.addMenuItem(resetMenuItem);

        final SpriteMenuItem quitMenuItem = new SpriteMenuItem(MENU_QUIT, this.mMenuQuitTextureRegion);
        quitMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        this.mMenuScene.addMenuItem(quitMenuItem);

        this.mMenuScene.buildAnimations();

        this.mMenuScene.setBackgroundEnabled(false);

        this.mMenuScene.setOnMenuItemClickListener(this);
    }

    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================
}
